#ifndef _ENTITY_H_
#define _ENTITY_H_

#include "Globals.h"
#include "Animation.h"

#include "BBox.h"
#include "SpawnInfo.h"

class Entity{
private:
    /// Last time the entity 'tick'ed
    Uint32 lastTickTime;

protected:
    /// Entity's x position
    int x;

    /// Entity's y position
    int y;

    /// Entity's horizontal velocity
    float u;

    /// Entity's vertical velocity
    float v;

	/// Entity's walking speed
	int walkingSpeed;

    /// Is the entity touching the ground? (Can they jump etc)
    bool touchingGround;

	/// The entities health
	byte health;

	/// Is the entity alive
	bool alive;

	/// Amount of points to give the player when this entity dies
	int pointsValue;

	/// When did the enemy die
	Uint32 timeOfDeath;

	/// Is the entity affected by gravity
	bool applyGravity;

    /// Should we draw the images flipped?
    bool flipped;

	bool expired;

    /** Implemented by subclasses. Returns the image for the Entity draw()
    method to draw to the screen. Should remain constant between tick()s */
    virtual Image* getCurrentImage() = 0;

    /// Implemented by subclasses. Performs specific actions for each subclass
    virtual void tick() = 0;

    void processForces();

	bool withinRange();

	// Called when an entity has been killed using the damage function
	virtual void handleDeath(){}

public:
	
	Entity(SpawnInfo spawnInfo = SpawnInfo());

	virtual ~Entity();

    /// Move the entity left
    void moveLeft();

    /// Move the entity right
    void moveRight();

    /// Controls timing, and calls the sub class's tick method at the right time
    void maybeTick();

    /// Draws the entity to the screen
    void draw();

    int getX(){ return x; }

    int getY(){ return y; }

	float getU(){ return u; }

    BBox getBoundingBox();

    bool collidesWith(Entity* other);

	bool isAlive(){ return alive; }

	void damage(byte amount, Entity* attacker, bool knockBack = true);

	bool hasExpired(){ return expired; }

	bool isFlipped(){ return flipped; }

	byte getHealth(){ return health; }

	void setApplyGravity(bool apply) { applyGravity = apply; }
};

#endif
